package bit.pja.wolfkill.Service;

import bit.pja.wolfkill.aop.Flag;
import bit.pja.wolfkill.entity.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class GameService {
    
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private ExecutorService executor = Executors.newFixedThreadPool(100);

    public String getContex(Game game) {
        StringBuilder str = new StringBuilder();
        for (User user : game.getUsers()) {
            str.append( user.getIndex() + "号玩家: ");
            if(user.getRole().isLived()) {
                str.append(" 存活");
            }else {
                str.append(" 死亡");
            }
            switch (user.getRole().getRoleId()) {
                case hunter:
                    str.append(" 猎人");
                    break;
                case villager:
                    str.append(" 村民");
                    break;
                case wolf:
                    str.append(" 狼人");
                    break;
                case wizard:
                    str.append(" 女巫");
                    break;
                case prophet:
                    str.append(" 预言家");
                    break;
            }
            str.append("\n");
        }
        System.out.println(str);
        return str.toString();
    }

    public void beginAGame(Game game) {
        executor.submit(new Runnable() {
            @Override
            public void run() {
                runGame(game);
            }
        });
    }

    public List<User> getValidUser(Game game) {
        List<User> users = new ArrayList<>();
        switch (game.getFlag()) {
            case Game.FLAG_WOLF: {
                users.addAll(getLivedUsers(game, RoleId.wolf));
                break;
            }
            case Game.FLAG_PROPHET: {
                users.addAll(getLivedUsers(game, RoleId.prophet));
                break;
            }
            case Game.FLAG_WIZZARD: {
                users.addAll(getLivedUsers(game, RoleId.wizard));
                break;
            }
            case Game.FLAG_VILLIGER: {
                users.addAll(getLivedUsers(game));
                break;
            }
            case Game.FLAG_HUNTER: {
                users.addAll(getLivedUsers(game, RoleId.hunter));
                break;
            }
        }
        StringBuilder str = new StringBuilder("请");
        for (User user : users) {
            str.append(user.getIndex() + "号 ");
        }
        str.append("玩家行动");
        logger.info(str.toString());
        return users;
    }
    
    
    public List<User> getLivedUsers(Game game) {
        List<User> users = new ArrayList<>();
        for(User user : game.getUsers()) {
            if(user.getRole().isLived()) {
                users.add(user);
            }
        }
        return users;
    }

    public List<User> getLivedUsers(Game game, RoleId roleId) {
        List<User> users = new ArrayList<>();
        for(User user : game.getUsers()) {
            if(user.getRole().isLived() && user.getRole().getRoleId().equals(roleId)) {
                users.add(user);
            }
        }
        return users;
    }

    

    public Set<User> getDeadUser(Game game){
        Set<User> deadUsers = new HashSet<>();
        //查询被狼人杀死的玩家
        User killedUser = getDeadUser(game, Record.WOLF);

        //查询被女巫解药的玩家  这里要保证女巫解药使用的正确
        User savedUser = getDeadUser(game, Record.WIZARD_DRUG);
        if (killedUser != savedUser) {
            killedUser.getRole().setLived(false);
            deadUsers.add(killedUser);
        } else {
            if(killedUser != null) {
                killedUser.getRole().setLived(true);
            }
        }

        //查询被女巫毒死的玩家
        User poisonUser = getDeadUser(game, Record.WIZARD_POISON);
        if (poisonUser != null) {
            poisonUser.getRole().setLived(false);
            poisonUser.getRole().setState(Role.HUNTER_NO);
            deadUsers.add(poisonUser);
        }

        //查询被放逐的玩家
        User votedUser = getDeadUser(game, Record.VILLIGER);
        if (votedUser != null) {
            votedUser.getRole().setLived(false);
            deadUsers.add(votedUser);
        }

        //查询被枪毙的玩家
        User shootUser = getDeadUser(game, Record.HUNTER);
        if (shootUser != null) {
            shootUser.getRole().setLived(false);
            deadUsers.add(shootUser);
        }

        return deadUsers;
    }

    public User getDeadUser(Game game, int recordId){
        Map<Integer, Integer> map = new HashMap<>();
        for(Record record : game.getRecords()) {
            if (record.getFlag() == recordId) {
                if (!map.containsKey(record.getToId())) {
                    map.put(record.getToId(), 1);
                } else {
                    map.put(record.getToId(), map.get(record.getToId())+1);
                }
            }
        }
        int index = -1, count = 0;
        for(Map.Entry<Integer, Integer> element : map.entrySet()) {
            if (count < element.getValue()) {
                count = element.getValue();
                index = element.getKey();
            }
        }
        return index == -1 ? null : game.getUsers().get(index);
    }

    public void progress(Game game, PutParams params) throws Exception{
        paramsValidate(game, params);
        insertRecord(game, params);
    }

    public void paramsValidate(Game game, PutParams params) throws Exception{
        User fromUser = game.getUsers().get(params.getFromIndex());
        User toUser = game.getUsers().get(params.getToIndex());
        Integer flag = params.getFlag();

        paramsValidate(game, fromUser, toUser, flag);
    }

    public void paramsValidate(Game game, User fromUser, User toUser, Integer flag) throws Exception{
        switch (game.getFlag()) {
            case Game.FLAG_WOLF: {
                validateUser(fromUser, RoleId.wolf, flag);
                break;
            }
            case Game.FLAG_PROPHET: {
                validateUser(fromUser, RoleId.prophet, flag);
                break;
            }
            case Game.FLAG_WIZZARD: {
                validateUser(fromUser, RoleId.wizard, flag);
                break;
            }
            case Game.FLAG_VILLIGER: {
                validateUser(fromUser, RoleId.villager, flag);
                break;
            }
            case Game.FLAG_HUNTER: {
                validateUser(fromUser, RoleId.hunter, flag);
                break;
            }
        }
        if (!toUser.getRole().isLived()) {
            throw new Exception("目标用户已死亡，操作无效");
        }
    }

    void validateUser(User user, RoleId roleId, Integer flag) throws Exception{
        switch (roleId) {
            case hunter: {
                if (!user.getRole().getRoleId().equals(RoleId.hunter)) {
                    throw new Exception(String.format("%d号玩家不是猎人", user.getIndex()));
                }
                break;
            }
            case wizard: {
                if (!user.getRole().getRoleId().equals(RoleId.wizard)) {
                    throw new Exception(String.format("%d号玩家不是女巫", user.getIndex()));
                }
                if (flag == PutParams.WIZARD_DRUG && !canDrug(user)) {
                    throw new Exception("女巫无法使用解药");
                }
                if (flag == PutParams.WIZARD_POISON && !canPoison(user)) {
                    throw new Exception("女巫无法使用毒药");
                }
                if(flag != PutParams.WIZARD_DRUG && flag != PutParams.WIZARD_POISON) {
                    throw new Exception("操作码无效");
                }
                break;
            }
            case prophet: {
                if (!user.getRole().getRoleId().equals(RoleId.prophet)) {
                    throw new Exception(String.format("%d号玩家不是预言家", user.getIndex()));
                }
                break;
            }
            case wolf: {
                if (!user.getRole().getRoleId().equals(RoleId.wolf)) {
                    throw new Exception(String.format("%d号玩家不是狼人", user.getIndex()));
                }
                break;
            }
        }
        if(!user.getRole().isLived()) {
            if(!user.getRole().getRoleId().equals(RoleId.hunter))
                throw new Exception(String.format("发起操作的%d号玩家已经死亡，操作无效",user.getIndex()));
        }
    }


    public boolean gameIsOver(Game game) {
        if(game.isOver()) {
            return true;
        }
        List<User> livedWolfs = getLivedUsers(game, RoleId.wolf);
        if(livedWolfs.isEmpty()) {
            game.setFlag(Game.FLAG_WOLF_LOSE);
            game.setOver(true);
            return true;
        }

        List<User> livedVilligers = getLivedUsers(game, RoleId.villager);
        if(livedVilligers.isEmpty()) {
            game.setFlag(Game.FLAG_WOLF_WIN);
            game.setOver(true);
            return true;
        }

        List<User> livedUsers = getLivedUsers(game);
        if(livedUsers.size() == livedWolfs.size() + livedVilligers.size()) {
            game.setFlag(Game.FLAG_WOLF_WIN);
            game.setOver(true);
            return true;
        }
        return false;
    }

    private boolean canDrug(User user) {
        return user.getRole().getState().equals(Role.WIZZARD_DRUG_POISON)
                || user.getRole().getState().equals(Role.WIZZARD_DRUG);
    }

    private boolean canPoison(User user) {
        return user.getRole().getState().equals(Role.WIZZARD_DRUG_POISON)
                || user.getRole().getState().equals(Role.WIZZARD_POISON);
    }

    public Record insertRecord(Game game, PutParams params) throws Exception{
        User fromUser = game.getUsers().get(params.getFromIndex());
        User toUser = game.getUsers().get(params.getToIndex());
        Integer flag = params.getFlag();

        return insertRecord(game, fromUser, toUser, flag);
    }

    private Record doHunter(Game game, User fromUser, User toUser, int flag){
        return game.insertRecord(new Record(fromUser.getIndex(), toUser.getIndex(), Record.HUNTER));
    }

    private Record doWolf(Game game, User fromUser, User toUser, int flag){
        return game.insertRecord(new Record(fromUser.getIndex(), toUser.getIndex(), Record.WOLF));
    }

    private Record doProphet(Game game, User fromUser, User toUser, int flag){
        if(!toUser.getRole().getRoleId().equals(RoleId.wolf)) {
            return game.insertRecord(new Record(fromUser.getIndex(), toUser.getIndex(), Record.PROPHET_GOOD));
        }
        else {
            return game.insertRecord(new Record(fromUser.getIndex(), toUser.getIndex(), Record.PROPHET_BAD));

        }
    }


    private Record doWizard(Game game, User fromUser, User toUser, Integer flag) throws Exception{
        if (flag == PutParams.WIZARD_DRUG) {
            Set<User> users = getDeadUser(game);
            if (!users.contains(users)) {
                throw new Exception("目标玩家没有死亡，不能使用解药");
            }
            if (canPoison(fromUser)) {
                fromUser.getRole().setState(Role.WIZZARD_POISON);
            } else {
                fromUser.getRole().setState(Role.WIZZARD_NO);
            }
            return game.insertRecord(new Record(fromUser.getIndex(), toUser.getIndex(), Record.WIZARD_DRUG));

        } else{
            if (canDrug(fromUser)) {
                fromUser.getRole().setState(Role.WIZZARD_DRUG);
            } else {
                fromUser.getRole().setState(Role.WIZZARD_NO);
            }
            return game.insertRecord(new Record(fromUser.getIndex(), toUser.getIndex(), Record.WIZARD_POISON));

        }
    }

    private Record doVilliger(Game game, User fromUser, User toUser, int flag){
        return game.insertRecord(new Record(fromUser.getIndex(), toUser.getIndex(), Record.VILLIGER));
    }



    boolean isRepeatOperation(Game game, User user) {
        for(Record record : game.getRecords()) {
            if(user.getIndex().equals(record.getFromId() )) {
                return true;
            }
        }
        return false;
    }

    public Record insertRecord(Game game, User fromUser, User toUser, Integer flag) throws Exception{
        if(isRepeatOperation(game, fromUser)) {
            throw new Exception(String.format("%d号玩家已经行动，请勿重复行动", fromUser.getIndex()));
        }
        switch (game.getFlag()) {
            case Game.FLAG_WOLF: {
                return doWolf(game, fromUser, toUser, flag);

            }
            case Game.FLAG_PROPHET: {
                return doProphet(game, fromUser, toUser, flag);

            }
            case Game.FLAG_WIZZARD: {
                return doWizard(game, fromUser, toUser, flag);
            }
            case Game.FLAG_VILLIGER: {
                return doVilliger(game, fromUser, toUser, flag);
            }
            case Game.FLAG_HUNTER: {
                return doHunter(game, fromUser, toUser, flag);
            }
        }
        return null;
    }
    
    public void runGame(Game game) {
        //检查游戏是否结束
        if (gameIsOver(game)) {
            return;
        }
        //进入下一阶段并提示
        changeFlag(game);
        //各阶段事件结算
        summaryOfEvent(game);
        runGame(game);
    }

    private void saveOldRecords(Game game) {
        game.getOldRecords().addAll(game.getRecords());
        game.getRecords().clear();
    }
    public void summaryOfEvent(Game game) {

        if (game.getFlag().equals(Game.FLAG_MORNING)
                || game.getFlag().equals(Game.FLAG_EVENING) ) {
            Set<User> deadUsers = getDeadUser(game);
            if(deadUsers.isEmpty() && game.getFlag().equals(Game.FLAG_MORNING) ){
                logger.info(String.format("第%d天是个平安夜", game.getDay()));
            }
            for(User user : deadUsers) {
                logger.info(String.format("%d号玩家死亡", user.getIndex()));
                if(gameIsOver(game)) {
                    //保存旧纪录
                    saveOldRecords(game);
                    return;
                }
                doUserSkill(game, user);
            }
            //保存旧纪录
            saveOldRecords(game);
        }
    }

    public void changeFlag(Game game){
        if(game.getFlag().equals(Game.FLAG_HUNTER)) {
            game.setFlag(game.getOldFlag());
        }
        game.setFlag(game.getFlag()+1);
        if(game.getFlag() > Game.FLAG_END) {
            game.setFlag(Game.FLAG_WOLF);
            game.setDay(game.getDay()+1);
        }

        if(game.getFlag() != Game.FLAG_EVENING && game.getFlag() != Game.FLAG_MORNING ) {
            getValidUser(game);
            delay(game.getWaitSecons());
        }

    }

    private void delay(int seconds) {
        try {
            logger.info(String.format("%d秒计时开始,请在规定时间内完成行动", seconds));
            Thread.sleep(seconds * 1000);
            logger.info(String.format("%d秒已到,自动进入下一阶段", seconds));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doUserSkill(Game game, User user) {
        if(user.getRole().getRoleId().equals(RoleId.hunter)) {
            if(user.getRole().getState().equals(Role.HUNTER_SHOOT)) {
                logger.info("猎人请开枪");
                game.setOldFlag(game.getFlag());
                game.setFlag(Game.FLAG_HUNTER);
                delay(game.getWaitSecons());
            }
        }
    }
}
